package com.back.service.impl;

import com.back.common.utils.JwtUtil;
import com.back.common.utils.MD5Util;
import com.back.common.utils.RedisUtil;
import com.back.common.utils.UserConverter;
import com.back.dto.LoginDTO;
import com.back.entity.User;
import com.back.mapper.UserMapper;
import com.back.service.IUserLoginLogService;
import com.back.service.IUserService;
import com.back.vo.JwtVo;
import com.back.vo.LoginResultVO;
import com.back.vo.UserVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author liyang
 * @since 2025-04-26
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private RedisUtil redisUtil;
    
    @Autowired
    private IUserLoginLogService userLoginLogService;
    
    // JWT令牌有效期（30分钟）
    private static final long JWT_EXPIRE = 30 * 60 * 1000L;
    
    // 刷新令牌有效期（7天）
    private static final long REFRESH_TOKEN_EXPIRE = 7 * 24 * 60 * 60 * 1000L;

    @Override
    public LoginResultVO login(LoginDTO loginDTO, HttpServletRequest request) {
        // 查询用户
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, loginDTO.getUsername())
                .or()
                .eq(User::getEmail, loginDTO.getUsername());
        
        User user = this.getOne(wrapper);
        log.info("用户登录: {}, 查询结果: {}", loginDTO.getUsername(), user != null ? "存在" : "不存在");
        
        // 验证用户存在性和密码
        if (user == null || !MD5Util.encrypt(loginDTO.getPassword()).equals(user.getPassword())) {
            throw new RuntimeException("用户名或密码错误");
        }
        
        // 检查用户状态
        if (!user.getStatus()) {
            throw new RuntimeException("账号已被禁用");
        }
        
        // 生成令牌
        String token = generateToken(user);
        String refreshToken = generateRefreshToken(user);
        
        log.info("生成的token: {}", token);
        
        // 记录登录日志
        userLoginLogService.recordLogin(user.getId(), request);
        
        // 返回登录结果
        return LoginResultVO.builder()
                .token(token)
                .refreshToken(refreshToken)
                .expiresIn((int)(JWT_EXPIRE / 1000))
                .user(UserConverter.convertToVO(user))
                .build();
    }
    
    @Override
    public LoginResultVO refreshToken(String refreshToken) {
        // 验证刷新令牌
        if (!JwtUtil.checkToken(refreshToken)) {
            throw new RuntimeException("刷新令牌已过期");
        }
        
        // 获取用户ID
        JwtVo jwtVo = JwtVo.fromClaims(JwtUtil.getTokenBody(refreshToken));
        Long userId = jwtVo.getId();
        
        // 从Redis获取刷新令牌进行比对
        String storedRefreshToken = redisUtil.get("refresh_token:" + userId);
        if (!refreshToken.equals(storedRefreshToken)) {
            throw new RuntimeException("刷新令牌无效");
        }
        
        // 获取用户信息
        User user = this.getById(userId);
        if (user == null || !user.getStatus()) {
            throw new RuntimeException("用户不存在或已被禁用");
        }
        
        // 生成新令牌
        String newToken = generateToken(user);
        String newRefreshToken = generateRefreshToken(user);
        
        return LoginResultVO.builder()
                .token(newToken)
                .refreshToken(newRefreshToken)
                .expiresIn((int)(JWT_EXPIRE / 1000))
                .user(UserConverter.convertToVO(user))
                .build();
    }
    
    @Override
    public boolean logout(Long userId) {
        // 清除Redis中的用户令牌
        redisUtil.del(userId.toString());
        // 清除刷新令牌
        redisUtil.del("refresh_token:" + userId);
        return true;
    }
    
    /**
     * 生成JWT令牌
     */
    private String generateToken(User user) {
        JwtVo jwtVo = new JwtVo();
        jwtVo.setId(user.getId());
        jwtVo.setName(user.getUsername());
        jwtVo.setEmail(user.getEmail());
        jwtVo.setTime(new Date().getTime());
        jwtVo.setRole(user.getRole());
        
        // 生成令牌
        String token = JwtUtil.getJwtToken(jwtVo, JWT_EXPIRE);
        
        // 存储令牌到Redis
        redisUtil.set(user.getId().toString(), token, JWT_EXPIRE / 1000);
        
        return token;
    }
    
    /**
     * 生成刷新令牌
     */
    private String generateRefreshToken(User user) {
        JwtVo jwtVo = new JwtVo();
        jwtVo.setId(user.getId());
        jwtVo.setName(user.getUsername());
        jwtVo.setEmail(user.getEmail());
        jwtVo.setTime(new Date().getTime());
        jwtVo.setRole(user.getRole());
        
        // 生成刷新令牌
        String refreshToken = JwtUtil.getJwtToken(jwtVo, REFRESH_TOKEN_EXPIRE);
        
        // 存储刷新令牌到Redis
        redisUtil.set("refresh_token:" + user.getId(), refreshToken, REFRESH_TOKEN_EXPIRE / 1000);
        
        return refreshToken;
    }
}
